#include"analyse.h"
#include <cmath>
#include <unordered_set>
#include <QSet>
#include <QDebug>

double Analyse::pi=3.14159265358979323846;
double Analyse::e=2.7182818284590452353602;
std::unordered_set<char> Analyse:: xKeySet={'x','y'};//可能为未知数的集合
std::unordered_set<char> Analyse:: numSet={'0','1','2','3','4','5','6','7','8','9','p','e'};
//std::unordered_set<char>是一个C++标准库容器，它表示一个无序的字符集合

//判断是否为运算符，包含 sin cos ,不会移动i
bool Analyse:: isOpt(const  std::string& expr,int i)
{
    switch (expr[i])
    {
        case '+':
        case '-':
        case '*':
        case '/':
        case '^':
        case 's':
        case 'c':
        case 't':
        case 'l':
        case '(':
        case ')':
            return true;
        default:
            return false;
    }
}

//判断是否为sin cas tan ln lg
bool Analyse:: isFuncOpt(char c)
{
    switch (c)
    {
        case 's':
        case 'c':
        case 't':
        case 'n':
        case 'g':
            return true;
        default:
            return false;
    }
}
//以上三个为判断
//接下来为获取，获取操作都需要后移i
//数字
double Analyse:: getNumber(const std::string& expr,int &i)//使用&i
{
    auto len=expr.length();//auto关键字来自动推断expr.length()函数返回值的类型
    double sign=1;//正或负
    if(i<len&&expr[i]=='-'){
        sign=-1;
        ++i;
    }
    if(i<len&&expr[i]=='p'){//pi
        i+=2;
        return pi*sign;
    }
    if(i<len&&expr[i]=='e'){
        ++i;
        return e*sign;
    }
    //处理实数
    double ret=0;
    while (i < len && expr[i]>='0'&&expr[i]<='9')
    {
        ret = ret * 10 + expr[i] - '0';
        i++;
    }
    //处理带小数的数
    double point=1;
    if(i<len&&expr[i]=='.')
    {
        ++i;
        while (i < len && expr[i]>='0'&&expr[i]<='9')
        {
            ret = ret * 10 + expr[i] - '0';
            point*=10;
            i++;
        }
    }
    return sign*ret/point;
}

//运算符
char Analyse:: getOpt(const std::string& expr,int &i)
{
    //解释同上
    auto len=expr.length();
    if(i<len)
        switch (expr[i])
        {
            case '+':
            case '-':
            case '*':
            case '/':
            case '^':
            case '(':
            case ')':
                ++i;
                return expr[i-1];
            case 's':
            case 'c':
            case 't':
                i+=3;
                return expr[i-3];
            case 'l'://lg和ln同运算等级，可以放一块
                i+=2;
                return expr[i-1];
        }
    return '?';
}

//检查后缀表达式的正确性，主要检查表达式的中的操作数和操作符号是否匹配
//后缀表达式自行学习哈
bool Analyse:: checkPost(const std::vector<std::any>& post)
{
    int n=0;//统计数的个数
    for(int i=0;i<post.size();++i)
    {
        auto &item=post[i];
        char c='?';
        if(item.type()==typeid(double))//判断是否为数
            ++n;
        else
        {
            c=std::any_cast<char>(item);
            if(xKeySet.find(c)!=xKeySet.end())//未知数 n++
                ++n;
            else
            {
                //符号 会取数 需要额外判断
                if(isFuncOpt(c))//sin cos
                {
                    if(n<1)//如cos1，只需要一个数即可构成运算
                        return false;
                }
                else if(n>=2)//其他操作需要两个数
                    --n;
                else//操作数不够 错误
                    return false;
            }
        }

    }
    return true;
}

//取得算式的后缀表达式
//后缀表达式，也称为逆波兰表达式，是将中缀表达式中的运算符移动到其相关的操作数之后的一种表达方式
//将中缀表达式转为后缀表达式，并且将数值也转换为double,expr 中缀表达式,ret 存储逆波兰表达式的结果
//检查表达式中的错误
bool Analyse:: getPostfix(std::string expr,std::vector<std::any>& ret)//逆波兰表达式
{
    bool isx=true;
    bool isy=true;
    ret.clear();//清空 ret 中的所有元素
    std::vector<char> stack;//符号栈
    int i=2;
    auto len=expr.length();
    try//在程序执行过程中可能发生的异常情况下，提供一种机制来控制异常并执行相应的处理
    {
        while (i<len)
        {
            if(numSet.find(expr[i])!=numSet.end()||xKeySet.find(expr[i])!=xKeySet.end())
            {
                if(expr[i]=='x')
                {
                    isx=false;
                    ++i;
                    ret.push_back('x');
                }
                else if(expr[i]=='y')
                {
                    isy=false;
                    ++i;
                    ret.push_back('y');
                }
                else
                    ret.push_back(getNumber(expr,i));//i在getnumber函数中就已经后移
            }
            else if(isOpt(expr,i))//如果是符号
            {
                if(expr[i]=='-'&&(expr[i-1]=='('||expr[i-1]=='='))
                {
                    double a=0;
                    ret.push_back(a);
                }
                int ii=i;
                char now= getOpt(expr,i);
                if(stack.empty()||now=='('||stack.back()=='(')// 如果当前符号栈为空或遇到左括号或栈顶是左括号，直接入符号栈
                    stack.push_back(now);
                else if(now ==')')//遇到右括号，则符号栈一直弹出运算符，直到遇到左括号，消除括号
                {
                    while(!stack.empty()&&stack.back()!='(')
                    {
                        ret.push_back(stack.back());
                        stack.pop_back();
                    }
                    if(!stack.empty())
                        stack.pop_back();//弹出左括号
                }
                else// 如果符号栈不空或者前一个不是左括号，就比较当前运算符和栈顶运算符的优先级
                {
                    if(getPriority(now)>getPriority(stack.back())||isFuncOpt(now)&&isFuncOpt(stack.back()))
                        // 当前运算符大于栈顶运算符的优先级，直接压入
                        stack.push_back(now);
                    else//当前运算符小于或等于栈顶运算符的优先级，则pop出栈顶符号，push到总栈中，将当前符号入符号栈
                    {
                        ret.push_back(stack.back());
                        stack.pop_back();
                        i=ii;//需要回溯，因为当前运算符还需要和符号栈次顶元素比较
                    }
                }
            }
            else//其他符号，存在错误
            {
                return false;
            }

        }
        //表达式扫描完毕，当符号栈不为空时，就顺序地从符号栈pop出元素push到总栈中
        while(!stack.empty())
        {
            ret.push_back(stack.back());
            stack.pop_back();
        }
    }
    catch (...)//当 try 块中抛出异常时，程序的执行会跳转到 catch 块，用于处理异常
    //论上应该包含更具体的异常处理代码，以正确处理可能发生的不同类型的异常
    {
        return false;
    }
    if(expr[0]=='z')
    {
        if(isy&&isx)
        {
            return false;
        }
    }
    if((expr[0]!='z'&&expr[0]!='x'&&expr[0]!='y')||expr[1]!='=')
    {
        return false;
    }
    return checkPost(ret);
}

//后缀表达式求值
//从左至右扫描表达式，遇到数字时，将数字压入堆栈，遇到运算符时，弹出栈顶的两个数，用运算符对它们做相应的计算
//&post 后缀表达式,&ret  返回结果,k 为未知数的形式,keyVal 未知数的值
//如果计算异常返回错误
bool Analyse:: getResult(const std::vector<std::any>& post ,double& ret, char k,double keyVal)
{
    std::vector<double> stack;
    ret=0;
    try
    {
        for(int i=0;i<post.size();++i)
        {
            auto &item=post[i];
            //处理数
            if(item.type()==typeid(double))
                stack.push_back(std::any_cast<double>(item));
            else
            {
                char c =std::any_cast<char>(item);
                if(c==k)//为未知数x
                    stack.push_back(keyVal);
                else//运算符
                {
                    double tmp=0;
                    //函数 一个数进行计算
                    if(isFuncOpt(c))
                    {
                        if(stack.size()<1)//至少需要一个数
                            return false;
                        double num=stack.back();
                        stack.pop_back();
                        switch (c)
                        {
                            case 's':
                                tmp=sin(num);
                                break;
                            case 'c':
                                tmp=cos(num);
                                break;
                            case 't':
                                tmp= tan(num);
                                break;
                            case 'g':
                                tmp=log10(num);
                                break;
                            case 'n':
                                tmp=log(num);
                                break;
                            default:
                                tmp=0;
                                break;
                        }
                    }
                    else // 双目运算符运算
                    {
                        if(stack.size()<2)
                            return false;
                        double num1=stack.back();
                        stack.pop_back();
                        double num2=stack.back();
                        stack.pop_back();
                        switch (c)
                        {
                            case '+':
                                tmp=num2+num1;
                                break;
                            case '-':
                                tmp=num2-num1;
                                break;
                            case '*':
                                tmp=num2*num1;
                                break;
                            case '/':
                                tmp=num2/num1;
                                break;
                            case '^':
                                tmp= pow(num2,num1);
                                break;
                            default:
                                tmp=0;
                                break;
                        }
                    }
                    stack.push_back(tmp);
                }
            }
        }
    }catch (...)
    {
        return false;
    }
    if(stack.size()!=1)
        return false;
    ret=stack.back();
    return true;
}

//优先级 '(' < 加减 < 乘除 < 函数 < 指数
int Analyse:: getPriority(char c)
{
    switch (c)
    {
        case '+':
        case '-':
            return 1;
        case '*':
        case '/':
            return 2;
        case 's':
        case 'c':
        case 't':
        case 'g':
        case 'n':
            return 3;
        case '^':
            return 4;
        default:
            return 0;
    }
}
